#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <ESP8266_Seniverse.h>

Adafruit_ILI9341 tft = Adafruit_ILI9341(D8, D1 , D3,D4,D2); //引脚分配
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
 

const char* ssid     = "XXXXXXXXX"; // 连接WiFi名
const char* password = "XXXXXXXXX";    // 连接WiFi密码
 
const char* host = "api.bilibili.com";     // 将要连接的服务器地址  
const int httpPort = 80;                   // 将要连接的服务器端口
//服务器地址、端口不用改      
 
String mid = "XXXXXXXXXXXXX";                  // 哔哩哔哩用户id

String reqUserKey = "XXXXXXXXXXX";   // 心知天气私钥
String reqLocation = "beijing";            // 城市
String reqUnit = "c";                      // 摄氏/华氏// 请将您需要连接的WiFi密码填入引号中

//以上需要用户自定义

Forecast forecast; // 建立Forecast对象用于获取心知天气信息
                                      
void connectWiFi(){
  WiFi.begin(ssid, password);                  // 启动网络连接
  Serial.print("Connecting to ");              // 串口监视器输出网络连接信息
  Serial.print(ssid); 
  Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接
  
  int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功
  while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 
    delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       
    Serial.print(i++);
    Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
  }                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。
                                               // 这个读秒是通过变量i每隔一秒自加1来实现的。                                              
  Serial.println("");                          // WiFi连接成功后
  Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。
  Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
  Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
}

void httpRequest(String reqRes){
  WiFiClient client;
 
  // 建立http请求信息
  String httpRequest = String("GET ") + reqRes + " HTTP/1.1\r\n" + 
                              "Host: " + host + "\r\n" + 
                              "Connection: close\r\n\r\n";
  Serial.println(""); 
  Serial.print("Connecting to "); Serial.print(host);
 
  // 尝试连接服务器
  if (client.connect(host, 80)){
    Serial.println(" Success!");
 
    // 向服务器发送http请求信息
    client.print(httpRequest);
    Serial.println("Sending request: ");
    Serial.println(httpRequest);  
 
    // 获取并显示服务器响应状态行 
    String status_response = client.readStringUntil('\n');
    Serial.print("status_response: ");
    Serial.println(status_response);
 
    // 使用find跳过HTTP响应头
    if (client.find("\r\n\r\n")) {
      Serial.println("Found Header End. Start Parsing.");
    }
    
    // 利用ArduinoJson库解析响应信息
     parseInfo(client); 
  } else {
    Serial.println(" connection failed!");
  }   
  //断开客户端与服务器连接工作
  client.stop(); 
}

// 利用ArduinoJson库解析响应信息
void parseInfo(WiFiClient client){
  const size_t capacity = JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 70;
  DynamicJsonDocument doc(capacity);
  
  deserializeJson(doc, client);
  
  int code = doc["code"]; 
  const char* message = doc["message"]; 
  int ttl = doc["ttl"]; 
  
  JsonObject data = doc["data"];
  long data_mid = data["mid"];
  int data_following = data["following"];
  int data_whisper = data["whisper"];
  int data_black = data["black"];
  int data_follower = data["follower"];
  tft.begin();
  tft.setCursor(0, 0);
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextSize(3);
  tft.println("=================");
  tft.print("Fans: ");              // 监视器输出粉丝数量
  tft.println(data_follower);
  tft.println(" ");
  tft.print("Followers: ");            // 监视器输出关注数量
  tft.println(data_following);
  tft.println(" ");  
  tft.print("BLACK:");       // 监视器输黑名单里的数量
  tft.println(data_black);
  tft.println(" ");    
  tft.print("=================");
}

void weatherdisplay(){
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  if(forecast.update()){  // 更新天气信息
    for(int i = 0; i < 2; i++){
      tft.setTextSize(2-i);
      tft.setTextColor(ILI9341_GREEN);
      tft.print(F("========Day ")); 
      tft.print(i);      
      tft.println(F("========"));     
      
      tft.print(F("Day Weather: "));
      tft.print(forecast.getDayText(i));  
      tft.print(F(" "));
      tft.println(forecast.getDayCode(i));  
      tft.print(F("Night Weather: "));
      tft.print(forecast.getNightText(i));  
      tft.print(F(" "));
      tft.println(forecast.getNightCode(i));  
      tft.print(F("High: "));
      tft.print(forecast.getHigh(i));
      tft.println(F(" C"));     
      tft.print(F("LOW: "));
      tft.print(forecast.getLow(i));  
      tft.println(F(" C"));
 
      tft.print(F("Rainfall: "));
      tft.print(forecast.getRain(i));  
      tft.println(F("%"));
      tft.print(F("Wind Direction: "));
      tft.println(forecast.getWindDirection(i));  
      tft.print(F("Wind Speed: "));
      tft.println(forecast.getWindSpeed(i));
      tft.print(F("Wind Scale: "));
      tft.println(forecast.getWindScale(i));    
      tft.print(F("Humidity: "));
      tft.println(forecast.getHumidity(i)); 
                    
      tft.print(F("Last Update: "));       
      tft.println(forecast.getLastUpdate());                
    }
    tft.print(F("Server Code: ")); 
    tft.println(forecast.getServerCode()); 
    tft.println(F("====================="));   
  } else {    // 更新失败
    tft.println("Update Fail...");   
    //tft.print("Server Response: ");          // 输出服务器响应状态码供用户查找问题
    //tft.println(weatherNow.getServerCode()); // 心知天气服务器错误代码说明可通过以下网址获取
  }                                             // https://docs.seniverse.com/api/start/error.html
}
  
void setup(){

  Serial.begin(9600);
  connectWiFi();    // 连接wifi
  forecast.config(reqUserKey, reqLocation, reqUnit);
}
void loop(){
  weatherdisplay();
  delay(20000);//延时20s
  String reqRes = "/x/relation/stat?vmid=" + mid 
                   +"&type=json";
 
  // 向哔哩哔哩API服务器服务器请求信息并对信息进行解析
  httpRequest(reqRes);
  delay(10000);
}
          
